package com.minelx.datamicroscope.querylanguage.data.sql;

import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.expr.SQLBinaryOpExpr;
import com.alibaba.druid.sql.ast.expr.SQLBinaryOperator;
import com.alibaba.druid.sql.ast.expr.SQLInListExpr;
import com.minelx.datamicroscope.querylanguage.data.BinaryOperatorCondition;
import com.minelx.datamicroscope.querylanguage.data.Condition;

import java.util.ArrayList;
import java.util.List;

public interface ConditionProvider {

	FieldBelongs left();

	String right();

	Condition toCondition();

	String literalKind();

	static ConditionProvider in(SQLInListExpr inListExpr) {
		return new InProvider(inListExpr);
	}

	static ConditionProvider eq(SQLExpr left, SQLExpr right) {
		return new BinaryOperatorProvider(left, "eq", right);
	}

	static ConditionProvider gt(SQLExpr left, SQLExpr right) {
		return new BinaryOperatorProvider(left, "gt", right);
	}

	static ConditionProvider ge(SQLExpr left, SQLExpr right) {
		return new BinaryOperatorProvider(left, "ge", right);
	}

	static ConditionProvider lt(SQLExpr left, SQLExpr right) {
		return new BinaryOperatorProvider(left, "lt", right);
	}

	static ConditionProvider le(SQLExpr left, SQLExpr right) {
		return new BinaryOperatorProvider(left, "le", right);
	}

	static ConditionProvider from(SQLExpr whereExpr) {
		if (whereExpr instanceof SQLInListExpr) {
			return in((SQLInListExpr) whereExpr);
		}
		SQLBinaryOpExpr binaryOpExpr = (SQLBinaryOpExpr) whereExpr;
		if (binaryOpExpr.getOperator() == SQLBinaryOperator.Equality) {
			return eq(binaryOpExpr.getLeft(), binaryOpExpr.getRight());
		} else if (binaryOpExpr.getOperator() == SQLBinaryOperator.GreaterThan) {
			return gt(binaryOpExpr.getLeft(), binaryOpExpr.getRight());
		} else if (binaryOpExpr.getOperator() == SQLBinaryOperator.GreaterThanOrEqual) {
			return ge(binaryOpExpr.getLeft(), binaryOpExpr.getRight());
		} else if (binaryOpExpr.getOperator() == SQLBinaryOperator.LessThan) {
			return lt(binaryOpExpr.getLeft(), binaryOpExpr.getRight());
		} else if (binaryOpExpr.getOperator() == SQLBinaryOperator.LessThanOrEqual) {
			return le(binaryOpExpr.getLeft(), binaryOpExpr.getRight());
		} else {
			throw new IllegalStateException("unexpected where expr: " + whereExpr);
		}
	}

	static List<ConditionProvider> list(SQLExpr where) {
		List<ConditionProvider> result = new ArrayList<>();
		fulfill(result, where);
		return result;
	}

	static void fulfill(List<ConditionProvider> conditions, SQLExpr whereExpr) {
		if (whereExpr instanceof SQLBinaryOpExpr &&
				((SQLBinaryOpExpr) whereExpr).getOperator() == SQLBinaryOperator.BooleanAnd) {
			SQLBinaryOpExpr binaryOpExpr = (SQLBinaryOpExpr) whereExpr;
			// AND expr
			fulfill(conditions, binaryOpExpr.getLeft());
			fulfill(conditions, binaryOpExpr.getRight());
		} else {
			conditions.add(from(whereExpr));
		}
	}
}
